using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application;
using Admin.NET.Application.Entity;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace Admin.Net.Plugin.Api;

[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class BIMeterService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<Building> _repBuild;

	private readonly SqlSugarRepository<ElectricMeter> _repEle;

	private readonly SqlSugarRepository<LabelManagement> _replabel;

	private readonly SqlSugarRepository<PowerConsumptionRecord> _rep;

	private readonly SqlSugarRepository<Collector> _repCollect;

	private readonly SqlSugarRepository<EarlyWarning> _repwring;

	public BIMeterService(SqlSugarRepository<ElectricMeter> repEle, SqlSugarRepository<LabelManagement> replabel, SqlSugarRepository<PowerConsumptionRecord> rep, SqlSugarRepository<Building> repBuild, SqlSugarRepository<Collector> repCollect, SqlSugarRepository<EarlyWarning> repwring)
	{
		_repBuild = repBuild;
		_repEle = repEle;
		_rep = rep;
		_replabel = replabel;
		_repCollect = repCollect;
		_repwring = repwring;
	}

	/// <summary>
	/// 获取标签数据
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/meterlabel", Name = "获取标签数据")]
	public async Task<LabelOutDto> GetEnergyConsumptionLabel()
	{
		DateTime nowMothTime = DateTime.Parse($"{DateTime.Now.Year}-{DateTime.Now.Month}-1");
		var result = await (from u in _rep.AsQueryable()
			where u.CreateTime >= nowMothTime
			group u by new { u.MeterId } into u
			select new
			{
				MeterId = u.MeterId,
				allEle = SqlFunc.AggregateSumNoNull(u.CombinedActiveTotalElectricEnergyDifference)
			}).ToListAsync();
		List<LabelMeterDto> meterInfo = await (from u in _repEle.AsQueryable()
			select new LabelMeterDto
			{
				LabelId = u.LabelId,
				Id = u.Id,
				allFee = 0m,
				LabelName = from s in SqlFunc.Subqueryable<LabelManagement>()
					where (long?)s.Id == u.LabelId
					select s.Name
			}).ToListAsync();
		LabelOutDto labelOutDto = new LabelOutDto();
		labelOutDto.AllEle = Math.Round(result.Sum(s => s.allEle), 2);
		meterInfo.ForEach(delegate(LabelMeterDto u)
		{
			u.allFee = Math.Round(result.Where(s => s.MeterId == u.Id).Sum(s => s.allEle), 2);
		});
		List<LabelItemOutDto> itemlist = (from u in meterInfo
			group u by new { u.LabelId, u.LabelName } into u
			select new LabelItemOutDto
			{
				LabelId = u.Key.LabelId,
				LabelName = u.Key.LabelName,
				Ele = u.Sum((LabelMeterDto s) => s.allFee)
			}).ToList();
		itemlist.ForEach(delegate(LabelItemOutDto u)
		{
			u.ELeRate = Math.Round(u.Ele / labelOutDto.AllEle, 2).ToString();
			u.Ele = Math.Round(u.Ele, 2);
		});
		labelOutDto.ListItem = itemlist;
		return labelOutDto;
	}

	/// <summary>
	/// 获取尖峰平谷总数据
	/// </summary>
	/// <param name="type">0是按日 1是当月 2是当年</param>
	/// <returns></returns>
	[HttpGet("/bi/meterlsit")]
	public async Task<MeterListDto> GetMeterList(int type)
	{
		DateTime dateTime = DateTime.Now;
		DateTime nextTime = dateTime.Date;
		switch (type)
		{
		case 1:
			nextTime = DateTime.Parse($"{DateTime.Now.Year}-{DateTime.Now.Month}-1");
			break;
		case 2:
			nextTime = DateTime.Parse($"{DateTime.Now.Year}-1-1");
			break;
		}
		ISugarQueryable<PowerConsumptionRecord> quary = from u in _rep.AsQueryable()
			where u.CreateTime <= dateTime && u.CreateTime >= nextTime
			select u;
		return await InitData(type, quary);
	}

	private async Task<MeterListDto> InitData(int type, ISugarQueryable<PowerConsumptionRecord> quary)
	{
		MeterListDto meterListDto = new MeterListDto();
		List<QuestMeterDto> quaryList = await quary.Select((PowerConsumptionRecord u) => new QuestMeterDto
		{
			CreateTime = u.CreateTime,
			CombinedActiveFlatElectricEnergyDifference = u.CombinedActiveFlatElectricEnergyDifference,
			CombinedActivePeakElectricEnergyDifference = u.CombinedActivePeakElectricEnergyDifference,
			CombinedActiveSharpElectricEnergyDifference = u.CombinedActiveSharpElectricEnergyDifference,
			CombinedActiveTotalElectricEnergyDifference = u.CombinedActiveTotalElectricEnergyDifference,
			CombinedActiveValleyElectricEnergyDifference = u.CombinedActiveValleyElectricEnergyDifference,
			Amount = u.Amount
		}).ToListAsync();
		List<MeterResult> results = new List<MeterResult>();
		switch (type)
		{
		case 0:
		{
			List<MeterResult> modelresult = (from u in quaryList
				group u by u.CreateTime.Value.Hour into u
				select new MeterResult
				{
					Key = u.Key.ToString(),
					FlatValue = u.Sum((QuestMeterDto u) => u.CombinedActiveFlatElectricEnergyDifference),
					PeakValue = u.Sum((QuestMeterDto u) => u.CombinedActivePeakElectricEnergyDifference),
					TipValue = u.Sum((QuestMeterDto u) => u.CombinedActiveSharpElectricEnergyDifference),
					TotalValue = u.Sum((QuestMeterDto u) => u.CombinedActiveTotalElectricEnergyDifference),
					ValleyValue = u.Sum((QuestMeterDto u) => u.CombinedActiveValleyElectricEnergyDifference),
					FeeValue = u.Sum((QuestMeterDto u) => u.Amount).Value
				}).ToList();
			int i;
			for (i = 0; i <= DateTime.Now.Hour; i++)
			{
				MeterResult model = modelresult.Where((MeterResult u) => u.Key == i.ToString()).FirstOrDefault();
				results.Add(new MeterResult
				{
					Key = i.ToString().PadLeft(2, '0') + ":00",
					FlatValue = Math.Round(model?.FlatValue ?? 0m, 2),
					PeakValue = Math.Round(model?.PeakValue ?? 0m, 2),
					TipValue = Math.Round(model?.TipValue ?? 0m, 2),
					TotalValue = Math.Round(model?.TotalValue ?? 0m, 2),
					ValleyValue = Math.Round(model?.ValleyValue ?? 0m, 2),
					FeeValue = Math.Round(model?.FeeValue ?? 0m, 2)
				});
			}
			break;
		}
		case 1:
		{
			List<MeterResult> modelresult = (from u in quaryList
				group u by u.CreateTime.Value.Day into u
				select new MeterResult
				{
					Key = u.Key.ToString(),
					FlatValue = u.Sum((QuestMeterDto u) => u.CombinedActiveFlatElectricEnergyDifference),
					PeakValue = u.Sum((QuestMeterDto u) => u.CombinedActivePeakElectricEnergyDifference),
					TipValue = u.Sum((QuestMeterDto u) => u.CombinedActiveSharpElectricEnergyDifference),
					TotalValue = u.Sum((QuestMeterDto u) => u.CombinedActiveTotalElectricEnergyDifference),
					ValleyValue = u.Sum((QuestMeterDto u) => u.CombinedActiveValleyElectricEnergyDifference),
					FeeValue = u.Sum((QuestMeterDto u) => u.Amount).Value
				}).ToList();
			int i;
			for (i = 1; i <= DateTime.Now.Day; i++)
			{
				MeterResult model = modelresult.Where((MeterResult u) => u.Key == i.ToString()).FirstOrDefault();
				results.Add(new MeterResult
				{
					Key = i + "日",
					FlatValue = Math.Round(model?.FlatValue ?? 0m, 2),
					PeakValue = Math.Round(model?.PeakValue ?? 0m, 2),
					TipValue = Math.Round(model?.TipValue ?? 0m, 2),
					TotalValue = Math.Round(model?.TotalValue ?? 0m, 2),
					ValleyValue = Math.Round(model?.ValleyValue ?? 0m, 2),
					FeeValue = Math.Round(model?.FeeValue ?? 0m, 2)
				});
			}
			break;
		}
		default:
		{
			List<MeterResult> modelresult = (from u in quaryList
				group u by u.CreateTime.Value.Month into u
				select new MeterResult
				{
					Key = u.Key.ToString(),
					FlatValue = u.Sum((QuestMeterDto u) => u.CombinedActiveFlatElectricEnergyDifference),
					PeakValue = u.Sum((QuestMeterDto u) => u.CombinedActivePeakElectricEnergyDifference),
					TipValue = u.Sum((QuestMeterDto u) => u.CombinedActiveSharpElectricEnergyDifference),
					TotalValue = u.Sum((QuestMeterDto u) => u.CombinedActiveTotalElectricEnergyDifference),
					ValleyValue = u.Sum((QuestMeterDto u) => u.CombinedActiveValleyElectricEnergyDifference),
					FeeValue = u.Sum((QuestMeterDto u) => u.Amount).Value
				}).ToList();
			int i;
			for (i = 1; i <= DateTime.Now.Month; i++)
			{
				MeterResult model = modelresult.Where((MeterResult u) => u.Key == i.ToString()).FirstOrDefault();
				results.Add(new MeterResult
				{
					Key = i + "月",
					FlatValue = Math.Round(model?.FlatValue ?? 0m, 2),
					PeakValue = Math.Round(model?.PeakValue ?? 0m, 2),
					TipValue = Math.Round(model?.TipValue ?? 0m, 2),
					TotalValue = Math.Round(model?.TotalValue ?? 0m, 2),
					ValleyValue = Math.Round(model?.ValleyValue ?? 0m, 2),
					FeeValue = Math.Round(model?.FeeValue ?? 0m, 2)
				});
			}
			break;
		}
		}
		meterListDto.FlatValue = results.Select((MeterResult u) => u.FlatValue).ToList();
		meterListDto.TotalValue = results.Select((MeterResult u) => u.TotalValue).ToList();
		meterListDto.TipValue = results.Select((MeterResult u) => u.TipValue).ToList();
		meterListDto.ValleyValue = results.Select((MeterResult u) => u.ValleyValue).ToList();
		meterListDto.PeakValue = results.Select((MeterResult u) => u.PeakValue).ToList();
		meterListDto.FeeValue = results.Select((MeterResult u) => u.FeeValue).ToList();
		meterListDto.Key = results.Select((MeterResult u) => u.Key).ToList();
		return meterListDto;
	}

	[HttpGet("/bi/meterco2")]
	public async Task<MeterCo2Dto> GetMeterList()
	{
		DateTime dateTime = DateTime.Now;
		DateTime nextTime = DateTime.Now.AddDays(-1.0);
		MeterCo2Dto meterCo2Dto = new MeterCo2Dto();
		var nowValue = await (from u in _rep.AsQueryable()
			where u.CreateTime <= dateTime && u.CreateTime >= ((DateTime)dateTime).Date
			group u by new { u.CreateTime.Value.Hour } into u
			select new
			{
				key = u.CreateTime.Value.Hour,
				value = SqlFunc.AggregateSumNoNull(u.ActivePowerAll)
			}).ToListAsync();
		var lastValue = await (from u in _rep.AsQueryable()
			where u.CreateTime <= nextTime && u.CreateTime >= ((DateTime)nextTime).Date
			group u by new { u.CreateTime.Value.Hour } into u
			select new
			{
				key = u.CreateTime.Value.Hour,
				value = SqlFunc.AggregateSumNoNull(u.ActivePowerAll)
			}).ToListAsync();
		List<string> key = new List<string>();
		List<decimal> NowValue = new List<decimal>();
		List<decimal> LastValue = new List<decimal>();
		int i;
		for (i = 0; i <= DateTime.Now.Hour; i++)
		{
			var nowmodel = nowValue.Where(u => u.key == i).FirstOrDefault();
			var lastmodel = lastValue.Where(u => u.key == i).FirstOrDefault();
			key.Add(i.ToString().PadLeft(2, '0') + ":00");
			NowValue.Add(Math.Round(nowmodel?.value ?? 0m, 2));
			LastValue.Add(Math.Round(lastmodel?.value ?? 0m, 2));
		}
		meterCo2Dto.Key = key;
		meterCo2Dto.LastValue = LastValue;
		meterCo2Dto.NowValue = NowValue;
		return meterCo2Dto;
	}

	/// <summary>
	/// 获取首页数据对比
	/// </summary>
	/// <param name="type">0是当日比较 1是当月比较 2是当年比较 co2</param>
	/// <returns></returns>
	[HttpGet("/bi/homedata")]
	public async Task<CheckMeterDto> GetHomeData(int type)
	{
		DateTime dateTime = DateTime.Now;
		DateTime nextTime = DateTime.Now.AddDays(-1.0);
		DateTime dateTimelast = DateTime.Now;
		DateTime nextTimelast = DateTime.Now.AddDays(-1.0);
		switch (type)
		{
		case 0:
			dateTime = DateTime.Now;
			nextTime = dateTime.Date;
			dateTimelast = dateTime.AddDays(-1.0);
			nextTimelast = dateTimelast.Date;
			break;
		case 1:
			dateTimelast = dateTime.AddMonths(-1);
			nextTimelast = DateTime.Parse($"{dateTimelast.Year}-{dateTimelast.Month}-1");
			nextTime = DateTime.Parse($"{DateTime.Now.Year}-{DateTime.Now.Month}-1");
			break;
		case 2:
			dateTimelast = dateTime.AddYears(-1);
			nextTimelast = DateTime.Parse($"{dateTimelast.Year}-1-1");
			nextTime = DateTime.Parse($"{DateTime.Now.Year}-1-1");
			break;
		}
		var nowValue = await (from u in _rep.AsQueryable()
			where u.CreateTime <= dateTime && u.CreateTime >= nextTime
			select new
			{
				total = SqlFunc.AggregateSumNoNull(u.CombinedActiveTotalElectricEnergyDifference),
				fee = SqlFunc.AggregateSumNoNull(u.Amount)
			}).FirstAsync();
		var lastValue = await (from u in _rep.AsQueryable()
			where u.CreateTime <= dateTimelast && u.CreateTime >= nextTimelast
			select new
			{
				total = SqlFunc.AggregateSumNoNull(u.CombinedActiveTotalElectricEnergyDifference),
				fee = SqlFunc.AggregateSumNoNull(u.Amount)
			}).FirstAsync();
		return new CheckMeterDto
		{
			Amount = Math.Round((nowValue?.fee).GetValueOrDefault(), 2),
			LastValue = Math.Round(lastValue?.total ?? 0m, 2),
			NowValue = Math.Round(nowValue?.total ?? 0m, 2)
		};
	}

	/// <summary>
	/// 昨日用电占比
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/electricityconsumptionratio")]
	public async Task<ElectricityConsumptionRatioDto> ElectricityConsumptionRatio(DateTime? date)
	{
		date = date ?? DateTime.Now.AddDays(-1.0).Date;
		ElectricityConsumptionRatioDto model = await (from u in _rep.AsQueryable()
			where u.CreateTime >= date && u.CreateTime <= ((DateTime?)date).Value.AddDays(1.0)
			select new ElectricityConsumptionRatioDto
			{
				FlatValue = SqlFunc.AggregateSumNoNull(u.CombinedActiveFlatElectricEnergyDifference),
				PeakValue = SqlFunc.AggregateSumNoNull(u.CombinedActivePeakElectricEnergyDifference),
				TipValue = SqlFunc.AggregateSumNoNull(u.CombinedActiveSharpElectricEnergyDifference),
				TotalValue = SqlFunc.AggregateSumNoNull(u.CombinedActiveTotalElectricEnergyDifference),
				ValleyValue = SqlFunc.AggregateSumNoNull(u.CombinedActiveValleyElectricEnergyDifference)
			}).FirstAsync();
		if (model != null)
		{
			model.FlatValue = Math.Round(model.FlatValue, 2);
			model.PeakValue = Math.Round(model.PeakValue, 2);
			model.TipValue = Math.Round(model.TipValue, 2);
			model.TotalValue = Math.Round(model.TotalValue, 2);
			model.ValleyValue = Math.Round(model.ValleyValue, 2);
		}
		return model ?? new ElectricityConsumptionRatioDto();
	}

	/// <summary>
	/// 获取电量使用top10
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/electricitytop")]
	public async Task<List<ElectricityTopDto>> GetElectricityTop()
	{
		DateTime nowMothTime = DateTime.Parse($"{DateTime.Now.Year}-{DateTime.Now.Month}-1");
		List<ElectricityTopDto> model = await (from u in _rep.AsQueryable()
			where u.CreateTime >= nowMothTime
			group u by new { u.MeterId } into u
			select new ElectricityTopDto
			{
				Value = SqlFunc.AggregateSumNoNull(u.CombinedActiveTotalElectricEnergyDifference),
				MeterId = u.MeterId
			} into u
			orderby u.Value descending
			select u).Take(10).ToListAsync();
		List<long> meterIds = model.Select((ElectricityTopDto u) => u.MeterId).ToList();
		var meterInfo = await (from u in _repEle.AsQueryable()
			where meterIds.Contains(u.Id)
			select new { u.Id, u.Name }).ToListAsync();
		model.ForEach(delegate(ElectricityTopDto u)
		{
			u.Name = meterInfo.Where(w => w.Id == u.MeterId).FirstOrDefault()?.Name ?? "";
		});
		BuildingData(model);
		return model;
	}

	private void BuildingData(List<ElectricityTopDto> building)
	{
		int index = 1;
		decimal lastValue = -1m;
		int count = 0;
		building.ForEach(delegate(ElectricityTopDto u)
		{
			if (lastValue == -1m)
			{
				u.Index = index;
			}
			else
			{
				if (lastValue == u.Value)
				{
					count++;
				}
				else
				{
					index = index + 1 + count;
					count = 0;
				}
				u.Index = index;
			}
			lastValue = u.Value;
			u.Value = Math.Round(u.Value, 2);
		});
	}

	/// <summary>
	/// 获取设备信息
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/device")]
	public async Task<BIDeviceInfoDto> GetDeviceInfo()
	{
		BIDeviceInfoDto bIDeviceInfoDto = new BIDeviceInfoDto();
		BIDeviceInfoDto bIDeviceInfoDto2 = bIDeviceInfoDto;
		bIDeviceInfoDto2.Region = await _repBuild.AsQueryable().CountAsync();
		var ele = await (from u in _repEle.AsQueryable()
			group u by new { u.SignalStatus } into u
			select new
			{
				key = u.SignalStatus,
				count = SqlFunc.AggregateCount(u.SignalStatus)
			}).ToListAsync();
		var collect = await (from u in _repCollect.AsQueryable()
			group u by new { u.Status } into u
			select new
			{
				key = u.Status,
				count = SqlFunc.AggregateCount(u.Status)
			}).ToListAsync();
		int waterCounnt = await _repwring.Context.Queryable<WaterDevice>().CountAsync();
		bIDeviceInfoDto.Error = ele.Where(u => u.key == 0).Sum(u => u.count) + collect.Where(u => u.key == 0).Sum(u => u.count);
		BIDeviceInfoDto bIDeviceInfoDto3 = bIDeviceInfoDto;
		bIDeviceInfoDto3.Alarm = await (from u in _repwring.AsQueryable()
			where u.Status != 2
			select u).CountAsync();
		bIDeviceInfoDto.Collect = collect.Sum(u => u.count);
		bIDeviceInfoDto.Meter = ele.Sum(u => u.count);
		bIDeviceInfoDto.WaterMeter = waterCounnt;
		return bIDeviceInfoDto;
	}

	/// <summary>
	///             最近预警 预警信息数量
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/alarmcountinfo")]
	public async Task<BIAlarmCountInfoDto> GeAlarmCountInfo()
	{
		BIAlarmCountInfoDto bIAlarmCountInfoDto = new BIAlarmCountInfoDto();
		int queryCount = (from x in _repwring.Context.Queryable<EarlyWarning>()
			where x.Status != 2 && x.WarningType == 1
			select x).Count();
		bIAlarmCountInfoDto.OffLine = queryCount;
		return bIAlarmCountInfoDto;
	}

	/// <summary>
	/// 最近预警预警信息
	/// </summary>
	/// <returns></returns>
	[HttpGet("/bi/alarminfo")]
	public async Task<SqlSugarPagedList<BIAlarmInfoDto>> GeAlarmInfo([FromQuery] BasePageInput input)
	{
		ISugarQueryable<EarlyWarning> query = from x in _repwring.Context.Queryable<EarlyWarning>()
			where x.Status != 2
			select x;
		query = query.OrderBy((EarlyWarning u) => u.Status).OrderBuilder(input);
		SqlSugarPagedList<BIAlarmInfoDto> result = await query.Select((EarlyWarning u) => new BIAlarmInfoDto
		{
			CreateTime = u.CreateTime.Value,
			Detial = u.WarningMsg,
			Id = u.WarningId.Value,
			Type = u.WarningTargetType
		}).ToPagedListAsync(input.Page, input.PageSize);
		List<long> collectId = (from u in result.Items
			where u.Type == 0
			select u.Id).Distinct().ToList();
		List<long> meterId = (from u in result.Items
			where u.Type == 1
			select u.Id).Distinct().ToList();
		List<BIDeviceDto> list = new List<BIDeviceDto>();
		if (collectId.Count > 0)
		{
			List<BIDeviceDto> list2 = list;
			list2.AddRange(await (from u in _repCollect.AsQueryable()
				where collectId.Contains(u.Id)
				select new BIDeviceDto
				{
					Id = u.Id,
					Name = u.Name
				}).ToListAsync());
		}
		if (meterId.Count > 0)
		{
			List<BIDeviceDto> list3 = list;
			list3.AddRange(await (from u in _repEle.AsQueryable()
				where meterId.Contains(u.Id)
				select new BIDeviceDto
				{
					Id = u.Id,
					Name = u.Name
				}).ToListAsync());
		}
		foreach (BIAlarmInfoDto item in result.Items)
		{
			BIDeviceDto info = list.Where((BIDeviceDto u) => u.Id == item.Id).FirstOrDefault();
			if (info != null)
			{
				item.MeterName = info.Name;
			}
		}
		return result;
	}
}
